﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.Threading;

namespace IPC.WinForm.WG
{
    #region 设备信息类

    /// <summary>
    /// 设备信息
    /// </summary>
    public abstract class BaseEquip
    {
        protected static string LOCK_FLAG = "EQUIP";        //线程同步锁定标识
        private readonly string BASE_EQUIP_CLOCKTYPE = System.Configuration.ConfigurationManager.AppSettings["BASE_EQUIP_CLOCKTYPE"];     //设备时钟类型，用于决定使用Thread、ThreadPool还是Timer

        #region 辅助类型
        /// <summary>
        /// 线程状态
        /// </summary>
        private enum threadState
        {
            none = 0,
            runing = 1,
            stoping = 2,
        }

        #endregion

        #region 字段定义

        private System.Threading.Thread _thisThread = null;         //读取设备线程对象，由App.Config中的BaseEquipType的值决定是采用Timer还是Thread，默认采用Thread
        private System.Timers.Timer _thisTimer = null;              //读取设备时钟对象，由App.Config中的BaseEquipType的值决定是采用Timer还是Thread

        #endregion

        #region 构造方法

        public BaseEquip()
        {
            this.Name = string.Empty;
            this.Project = string.Empty;
            this.Main = new Main();
            this.Group = new Dictionary<string, Group>();
            this.State = false;

            if (!String.IsNullOrEmpty(BASE_EQUIP_CLOCKTYPE) && BASE_EQUIP_CLOCKTYPE == "Timer")
            {
                this._thisTimer = new System.Timers.Timer();
                this._thisTimer.Elapsed += delegate(object sender, System.Timers.ElapsedEventArgs e)
                {
                    try
                    {
                        Read();
                    }
                    catch (Exception ex)
                    {
                        RunOnExcept(ex);
                    }
                };
            }
        }

        #endregion

        #region 属性定义

        /// <summary>
        /// 设备名称
        /// </summary>
        [Caption("")]
        public string Name { get; set; }
        /// <summary>
        /// 项目名称
        /// </summary>
        public string Project { get; set; }
        /// <summary>
        /// 设备主信息
        /// </summary>
        public Main Main { get; set; }
        /// <summary>
        /// 设备数据块信息
        /// </summary>
        public Dictionary<string, Group> Group { get; set; }
        /// <summary>
        /// 设备状态
        /// </summary>
        public bool State { get; protected set; }
        /// <summary>
        /// 是否最小读取频率的设备
        /// </summary>
        public bool IsMinReadHZ { get; set; }

        public string IP { get; set; }

        public string Rack { get; set; }

        public string Slot { get; set; }

        #endregion

        #region 接口方法、事件定义
        /// <summary>
        /// 打开设备
        /// </summary>
        /// <returns></returns>
        public abstract bool Open();
        /// <summary>
        /// 读取信息
        /// </summary>
        /// <param name="block">数据块</param>
        /// <param name="start">起始地址</param>
        /// <param name="len">长度</param>
        /// <param name="buff">读取返回信息</param>
        /// <returns></returns>
        public abstract bool Read(string block, int start, int len, out object[] buff);
        /// <summary>
        /// 读取信息
        /// </summary>
        /// <param name="block">数据块</param>
        /// <param name="start">起始地址</param>
        /// <param name="len">长度</param>
        /// <param name="buff">读取返回信息</param>
        /// <returns></returns>
        public virtual bool Read(string block, int start, int len, out ushort[] buff)
        {
            buff = new ushort[len];
            return false;
        }
        /// <summary>
        /// 写入信息
        /// </summary>
        /// <param name="block">数据块</param>
        /// <param name="start">起始地址</param>
        /// <param name="buff">长度</param>
        /// <returns></returns>
        public abstract bool Write(int block, int start, object[] buff);
        /// <summary>
        /// 写入信息
        /// </summary>
        /// <param name="block">数据块</param>
        /// <param name="start">起始地址</param>
        /// <param name="buff">长度</param>
        /// <returns></returns>
        public virtual bool Write(int block, int start, ushort[] buff)
        {
            return false;
        }
        public virtual bool Write(string runName,string block, string dataType, object value)
        {
            return false;
        }
        /// <summary>
        /// 关闭设备
        /// </summary>
        public abstract void Close();
        /// <summary>
        /// 读取信息委托
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public delegate void ReadDataHandler(object sender, ReadEventArgs e);
        /// <summary>
        /// 读取信息事件
        /// </summary>
        public event ReadDataHandler EquipReadData;
        /// <summary>
        /// 异常委托
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public delegate void ExceptHandler(object sender, Exception e);
        /// <summary>
        /// 异常事件
        /// </summary>
        public event ExceptHandler OnExcept;

        #endregion

        #region 事件参数初始化
        /// <summary>
        /// 初始化读取信息参数
        /// </summary>
        private void IniReadEventArgs()
        {
        }
        /// <summary>
        /// 刷新事件参数值
        /// </summary>
        /// <param name="d"></param>
        public void RefreshEventArgsValue(Data d)
        {
        }

        #endregion

        #region 数据格式化方法
        private string FormatMethod(Data fdata)
        {
            string Result = fdata.Method;
            return Result;
        }
        #endregion

        #region 辅助方法

        private object[] GetRowValue(string key, object[] buff)
        {
            foreach (DataRow dr in buff)
            {
                if (dr["ssKey"].ToString().Equals(key))
                {
                    return new object[] { dr["ssValue"] };
                }
            }
            return null;
        }
        private object[] GetOpcValue(string key, object[] buff)
        {
            object[] Result = new object[1];
            foreach (var d in buff)
            {
                string[] keyValue = d.ToString().Split(':');
                if (keyValue.Length > 1)
                {
                    if (keyValue[0] == key)
                    {
                        Result[0] = keyValue[1];
                    }
                }
            }
            return Result;
        }
        private object[] GetDataValue(Data d, object[] buff)
        {
            object[] Result = new object[d.Len];
            for (int i = 0; i < d.Len; i++)
            {
                int index = d.Start + i;
                Result[i] = buff[index];
            }
            return Result;
        }
        private bool BuffEqual(object[] obj1, object[] obj2)
        {
            if (obj1 == null || obj2 == null)
            {
                if (obj1 == null && obj2 == null)
                {
                    return true;
                }
                if (obj1 != null || obj2 != null)
                {
                    return false;
                }
            }
            if (obj1.Length != obj2.Length)
            {
                return false;
            }
            for (int i = 0; i < obj1.Length; i++)
            {
                if (obj1[i] == null || obj2[i] == null)
                {
                    if (obj1[i] != null || obj2[i] != null)
                    {
                        return false;
                    }
                    continue;
                }
                if (obj1[i].GetType() != obj2[i].GetType())
                {
                    return false;
                }
                if (!obj1[i].Equals(obj2[i]))
                {
                    return false;
                }
            }
            return true;
        }
        private object GetValue(Data fdata, object[] buff)
        {
            return null;
        }
        /// <summary>
        /// 读取信息数据更新
        /// </summary>
        /// <param name="group"></param>
        /// <param name="buff"></param>
        private int FormatData(Group group, object[] buff)
        {
            return 0;
        }
        private int FormatData(Data data, object[] buff)
        {
            int Result = 0;
            return Result;
        }

        /// <summary>
        /// 异常时调用
        /// </summary>
        /// <param name="ex"></param>
        private void RunOnExcept(Exception ex)
        {
            if (OnExcept != null)
            {
                OnExcept(this, ex);
            }
        }

        #endregion

        #region 数据读取
        public object ReadData(Data data)
        {
            Group group = data.Group;
            if (group.Len > 0 && (group.Access == System.IO.FileAccess.Read || group.Access == System.IO.FileAccess.ReadWrite))
            {
                object[] buff = new object[group.Len];
                if (Read(group.Block, group.Start, group.Len, out buff))
                {
                    group.Value = buff;
                    FormatData(data, buff);
                }
            }
            return data.Value;
        }
        /// <summary>
        /// 数据读取
        /// </summary>
        private bool Read(bool isReadAll)
        {
            bool readResult = true;
            try
            {
                int iReadGroupCount = 0;
                foreach (Group group in this.Group.Values)
                {
                    if (group.Len > 0 && (group.IsAutoRead || isReadAll)
                        && (group.Access == System.IO.FileAccess.Read || group.Access == System.IO.FileAccess.ReadWrite))
                    {
                        object[] buff = new object[group.Len];
                        if (Read(group.Block, group.Start, group.Len, out buff))
                        {
                            #region 回放数据库每个频率周期只触发一次读取就中断处理，Display为回放设备品牌

                            if (this.Main.Brand.Equals("Display", StringComparison.CurrentCultureIgnoreCase))
                            {
                                break;
                            }

                            #endregion

                            group.Value = buff;
                            if (FormatData(group, buff) > 0)
                            {
                                iReadGroupCount++;
                            }
                        }
                        else 
                        {
                            readResult = false;     //只要有读取失败的数据块，则把这轮读取结果设置为false
                        }

                        #region 回放数据库每个频率周期只触发一次读取就中断处理，Display为回放设备品牌

                        if (this.Main.Brand.Equals("Display", StringComparison.CurrentCultureIgnoreCase))
                        {
                            break;
                        }

                        #endregion
                    }
                }
            }
            catch (Exception ex)
            {
                RunOnExcept(ex);
            }
            finally
            {
            }
            return readResult;
        }

        /// <summary>
        /// 读取IsAutoRead=true的块
        /// </summary>
        /// <returns>成功返回true，失败返回false</returns>
        public bool Read()
        {
            return Read(false);
        }

        /// <summary>
        /// 读取所有块的数据
        /// </summary>
        /// <returns>成功返回true，失败返回flase</returns>
        public bool ReadAll()
        {
            return Read(true);
        }

        private object getRowValue(DataTable dt, string key)
        {
            object Result = null;
            foreach (DataRow row in dt.Rows)
            {
                if (row["ssKey"].ToString() == key)
                {
                    return row["ssValue"];
                }
            }
            return Result;
        }

        #endregion

        #region 设备启动、停止方法定义
        /// <summary>
        /// 线程状态
        /// </summary>
        private threadState threadstate = threadState.none;

        /// <summary>
        /// 线程启动
        /// </summary>
        public void Start()
        {
            if (!String.IsNullOrEmpty(BASE_EQUIP_CLOCKTYPE) && BASE_EQUIP_CLOCKTYPE == "Timer")
            {
                //定时器启动
                threadstate = threadState.runing;
                if (this.IsMinReadHZ == false)
                {
                    try
                    {
                        Read();  //提前执行一次设备读取
                    }
                    catch (Exception ex)
                    {
                        RunOnExcept(ex);
                    }
                }
                this._thisTimer.Interval = this.Main.ReadHz;
                this._thisTimer.Start();
            }
            else if (!String.IsNullOrEmpty(BASE_EQUIP_CLOCKTYPE) && BASE_EQUIP_CLOCKTYPE == "Thread")
            {
                //线程启动
                if (threadstate == threadState.runing)
                {
                    return;
                }
                for (int i = 0; i < 100; i++)
                {
                    if (threadstate == threadState.none)
                    {
                        break;
                    }
                    Thread.Sleep(200);
                }
                threadstate = threadState.runing;
                //ThreadPool.QueueUserWorkItem(new WaitCallback(OnReadTimerTick));
                try
                {
                    Read();
                }
                catch (Exception ex)
                {
                    RunOnExcept(ex);
                }
                this._thisThread = new Thread(new ThreadStart(OnReadTimerTick));
                this._thisThread.Start();
            }
            else
            {
                if (threadstate == threadState.runing)
                {
                    return;
                }
                for (int i = 0; i < 100; i++)
                {
                    if (threadstate == threadState.none)
                    {
                        break;
                    }
                    Thread.Sleep(200);
                }
                threadstate = threadState.runing;
                ThreadPool.QueueUserWorkItem(new WaitCallback(OnReadTimerTick));
            }
        }
        /// <summary>
        /// 线程结束
        /// </summary>
        public void Stop()
        {
            if (threadstate == threadState.runing)
            {
                threadstate = threadState.stoping;
            }
            if (!String.IsNullOrEmpty(BASE_EQUIP_CLOCKTYPE) && BASE_EQUIP_CLOCKTYPE == "Timer")
            {
                try
                {
                    this._thisTimer.Stop();
                }
                catch (Exception ex)
                {
                    
                }
            }
            else if (!String.IsNullOrEmpty(BASE_EQUIP_CLOCKTYPE) && BASE_EQUIP_CLOCKTYPE == "Thread")
            {
                try
                {
                    if (this._thisThread != null && this._thisThread.ThreadState == ThreadState.Running)
                    {
                        this._thisThread.Abort();
                        this._thisThread = null;
                    }
                    else if (this._thisThread != null && this._thisThread.ThreadState == ThreadState.Suspended)
                    {
                        this._thisThread.Resume();
                        this._thisThread.Abort();
                        this._thisThread = null;
                    }
                }
                catch (Exception ex)
                {
                    
                }
            }
            else
            {
                if (threadstate == threadState.runing)
                {
                    threadstate = threadState.stoping;
                }
            }
        }

        /// <summary>
        /// 修改设备
        /// </summary>
        /// <param name="readHz"></param>
        public void SetMainReadHZ(int readHz)
        {
            if (!String.IsNullOrEmpty(BASE_EQUIP_CLOCKTYPE) && BASE_EQUIP_CLOCKTYPE == "Timer")
            {
                this._thisTimer.Interval = readHz;
            }
            this.Main.ReadHz = readHz;
            try
            {
                Read();
            }
            catch (Exception ex)
            {
                RunOnExcept(ex);
            }
        }
        /// <summary>
        /// 线程睡眠，即延迟
        /// </summary>
        private void Delay()
        {
            DateTime now = DateTime.Now;
            while (true)
            {
                if (this.Main.ReadHz != int.MaxValue)
                {
                    break;
                }
                Thread.Sleep(200);
            }
            Thread.Sleep(this.Main.ReadHz);
            return;
        }
        /// <summary>
        /// 线程运行处理业务
        /// </summary>
        public void OnReadTimerTick()
        {
            while (true)
            {
                if (threadstate != threadState.runing)
                {
                    RunOnExcept(new Exception("线程停止"));
                    threadstate = threadState.none;
                    return;
                }
                try
                {
                    Read();
                }
                catch (Exception ex)
                {
                    RunOnExcept(ex);
                }
                Delay();
            }
        }

        /// <summary>
        /// 线程运行处理业务
        /// </summary>
        public void OnReadTimerTick(object sender)
        {
            while (true)
            {
                if (threadstate != threadState.runing)
                {
                    RunOnExcept(new Exception("线程停止"));
                    threadstate = threadState.none;
                    return;
                }
                try
                {
                    Read();
                }
                catch (Exception ex)
                {
                    RunOnExcept(ex);
                }
                Delay();
            }
        }

        #endregion

        #region 析构方法
        /// <summary>
        /// 析构方法
        /// </summary>
        ~BaseEquip()
        {
            try
            {
                this.Stop();
                this.Close();
                System.GC.Collect();
            }
            catch (Exception ex)
            {
                
            }
        }

        #endregion
    }

    #endregion

    #region 数据读取事件参数类
    /// <summary>
    /// 数据读取事件参数
    /// </summary>
    public class ReadEventArgs
    {
        public ReadEventArgs()
        {
            this.Data = new Dictionary<string, object>();
        }
        /// <summary>
        /// 读取数据信息
        /// </summary>
        public Dictionary<string, object> Data { get; set; }
    }

    #endregion
}
